#include <../lib/igloo/igloo.h>
#include "../../HashExtensible/HashExtensible.h"
#include "../../HashExtensible/Cubeta.h"
#include "../../HashExtensible/RegistroCubeta.h"
#include "../../Archivos/Configuracion.h"
#include "../../Entidades/IRegistroIndice.h"

using namespace igloo;
using namespace Hash;
Context(HashExtensibleTest)
{
	HashExtensible* hashExtensible;
	string pathHash;
	string pathTabla;
	string pathCubetasLibres;
	string nombre;
	Configuracion* config;

	void SetUp() {
		nombre = "Prueba";
		config = Configuracion::getInstancia("archivoConfiguracionTestHash.txt");
		pathHash = config->getPathHashExtensible() + "hash" + nombre + ".bin";
		pathTabla = config->getPathHashExtensible() + "tablaHash" + nombre + ".bin";
		pathCubetasLibres = config->getPathHashExtensible() + "cubetasLibres" + nombre + ".bin";
		hashExtensible = new HashExtensible(nombre);
	}

	void TearDown() {
		remove(pathHash.c_str());
		remove(pathTabla.c_str());
		remove(pathCubetasLibres.c_str());
		delete hashExtensible;
		delete config;
	}

	Spec(insertarYExiste) {
		hashExtensible->insertar("091011Presidente", 7);
		Assert::That(hashExtensible->existe("091011Presidente"));
	}

	Spec(insertarYeliminar) {
		hashExtensible->insertar("091011Presidente", 7);
		hashExtensible->eliminar("091011Presidente", 7);
		Assert::That(hashExtensible->existe("091011Presidente"), Is().EqualTo(false));
		hashExtensible->exportarTxt("pruebaHashTxt1");
	}

	Spec(exportar2Txt) {
		hashExtensible->insertar("091011Presidente", 7);
		hashExtensible->exportarTxt("pruebaHashTxt2");
		Assert::That(1);
	}

	Spec(desborde) {
		hashExtensible->insertar("091011Presidente", 7);
		hashExtensible->exportarTxt("pruebaHashTxt3");
		hashExtensible->insertar("091011Presidente", 8);
		hashExtensible->exportarTxt("pruebaHashTxt3");
		hashExtensible->insertar("093011Presidente", 7);
		hashExtensible->exportarTxt("pruebaHashTxt3");
		hashExtensible->insertar("094011Presidente", 7);
		hashExtensible->exportarTxt("pruebaHashTxt3");

		Assert::That(1);
	}

	Spec(desbordePorOffsetsConTDAFull) {

		/*La cubeta desborda al insertar un offset
		 *Tiene el  tamanio de dispersion mayor que el tamanio de la tabla
		 */
		hashExtensible->insertar("AAAAAAAA", 7);
		hashExtensible->exportarTxt("pruebaHashTxt4");
		hashExtensible->insertar("AAAAAAAA", 8);
		hashExtensible->exportarTxt("pruebaHashTxt4");
		hashExtensible->insertar("BBBBBBBB", 7);
		hashExtensible->exportarTxt("pruebaHashTxt4");
		hashExtensible->insertar("CCCCCCCC", 7);
		hashExtensible->exportarTxt("pruebaHashTxt4");

		hashExtensible->insertar("CCCCCCCC", 5);
		hashExtensible->exportarTxt("pruebaHashTxt4");
		hashExtensible->insertar("CCCCCCCC", 9);
		hashExtensible->exportarTxt("pruebaHashTxt4");
		hashExtensible->insertar("CCCCCCCC", 2);
		hashExtensible->exportarTxt("pruebaHashTxt4");
		hashExtensible->insertar("CCCCCCCC", 3);
		hashExtensible->insertar("CCCCCCCC", 4);
		hashExtensible->insertar("CCCCCCCC", 5);
		hashExtensible->insertar("CCCCCCCC", 6);
		hashExtensible->exportarTxt("pruebaHashTxt4");

		hashExtensible->insertar("CCCCCCCC", 1);
		hashExtensible->exportarTxt("pruebaHashTxt4");

		Assert::That(1);
	}

	Spec(desbordePorOffsetsConTDMenor) {

		/*La cubeta desborda al insertar un offset
		 *Tiene el  tamanio de dispersion menor que el tamanio de la tabla
		 */
		hashExtensible->insertar("AAAAAAAA", 7);
		hashExtensible->insertar("AAAAAAAA", 8);
		hashExtensible->exportarTxt("pruebaHashTxt5");

		hashExtensible->insertar("BBBBBBBB", 7);
		hashExtensible->insertar("BBBBBBBB", 1);
		hashExtensible->insertar("BBBBBBBB", 2);
		hashExtensible->insertar("BBBBBBBB", 3);
		hashExtensible->insertar("BBBBBBBB", 4);
		hashExtensible->exportarTxt("pruebaHashTxt5");

		hashExtensible->insertar("CCCCCCCC", 7);
		hashExtensible->exportarTxt("pruebaHashTxt5");

		hashExtensible->insertar("CCCCCCCC", 5);
		hashExtensible->insertar("CCCCCCCC", 9);
		hashExtensible->insertar("CCCCCCCC", 2);
		hashExtensible->insertar("CCCCCCCC", 3);
		hashExtensible->insertar("CCCCCCCC", 4);
		hashExtensible->insertar("CCCCCCCC", 5);
		hashExtensible->insertar("CCCCCCCC", 6);
		hashExtensible->exportarTxt("pruebaHashTxt5");

		hashExtensible->insertar("DDDDDDDD", 1);
		hashExtensible->insertar("DDDDDDDD", 2);
		hashExtensible->exportarTxt("pruebaHashTxt5");

		Assert::That(1);
	}

	Spec(modificarOffset) {

		//Modifico en distintas posiciones
		hashExtensible->insertar("Primera Clave", 46);
		hashExtensible->insertar("Primera Clave", 125);
		hashExtensible->insertar("Primera Clave", 789);
		hashExtensible->insertar("Segunda Clave", 789);
		hashExtensible->exportarTxt("specModificarOffset");
		hashExtensible->modificar("Primera Clave", 125, 855);
		hashExtensible->exportarTxt("specModificarOffset");
		hashExtensible->modificar("Segunda Clave", 789, 111);
		hashExtensible->modificar("Primera Clave", 46, 147);
		hashExtensible->exportarTxt("specModificarOffset");

		//Compruebo que los offsets hallan cambiado
		IRegistroIndice* resultado = hashExtensible->buscar("Segunda Clave");
		Assert::That(resultado->getOffsets()->at(0) == 111);
		delete resultado;

		//Compruebo que los offsets hallan cambiado
		resultado = hashExtensible->buscar("Primera Clave");
		Assert::That(resultado->getOffsets()->at(1) == 855);
		delete resultado;

		//Compruebo que los offsets hallan cambiado
		resultado = hashExtensible->buscar("Primera Clave");
		Assert::That(resultado->getOffsets()->at(0) == 147);
		delete resultado;

		//Trato de modificar una clave inexistente
		bool estado = hashExtensible->modificar("Tercera Clave", 125, 222);
		Assert::That(estado, Is().EqualTo(false));

		//Trato de modificar un offset inexistente
		estado = hashExtensible->modificar("Primera Clave", 33, 789);
		Assert::That(estado, Is().EqualTo(false));

	}

	Spec(eliminar) {
		//No existe la clave que se quiere eliminar
		bool accion = hashExtensible->eliminar("Primera Clave", 46);
		Assert::That(accion, Is().EqualTo(false));
		hashExtensible->exportarTxt("specEliminar");

		//Existe la clave pero no existe el offset
		hashExtensible->insertar("Primera Clave", 46);
		accion = hashExtensible->eliminar("Primera Clave", 98);
		Assert::That(accion, Is().EqualTo(false));
		hashExtensible->exportarTxt("specEliminar");

		//Existen la clave y el offset, la cubeta no queda vacia, el registro tampoco
		hashExtensible->insertar("Primera Clave", 46);
		hashExtensible->insertar("Primera Clave", 125);
		hashExtensible->insertar("Primera Clave", 789);
		hashExtensible->insertar("Segunda Clave", 856);
		accion = hashExtensible->eliminar("Primera Clave",125);
		Assert::That(accion, Is().EqualTo(true));
		hashExtensible->exportarTxt("specEliminar");

		//Lo veo como registro cubeta para que busque el offset
		RegistroCubeta* registro = (RegistroCubeta*)hashExtensible->buscar("Primera Clave");
		int resultado= registro->buscar(125);
		Assert::That(resultado, Is().EqualTo(-1));
		delete registro;

	//	int cubetasLibres = hashExtensible->cubetasLibres->getCantidadEstructurasLibres();
	//	Assert::That(cubetasLibres, Is().EqualTo(0));

		//Existen la clave y el offset, la cubeta queda vacia, se puede liberar
		accion = hashExtensible->eliminar("Segunda Clave",856);
		Assert::That(accion, Is().EqualTo(true));

		IRegistroIndice* registro2 = hashExtensible->buscar("Segunda Clave");
		Assert::That(registro2->getOffsets()->size(), Is().EqualTo(0));
		hashExtensible->exportarTxt("specEliminar");
		delete registro2;

	//	cubetasLibres = hashExtensible->cubetasLibres->getCantidadEstructurasLibres();
	//	Assert::That(cubetasLibres, Is().EqualTo(1));


		//Existe la clave y el offset, la cubeta no queda vacia, el registro si
		hashExtensible->insertar("Cl", 74);
		hashExtensible->insertar("ve 2",412);
		hashExtensible->insertar("la 3", 12463);
		hashExtensible->exportarTxt("specEliminar");
		accion = hashExtensible->eliminar("Cl",74);
		Assert::That(accion, Is().EqualTo(true));

		IRegistroIndice* registro3 = hashExtensible->buscar("Cl");
		Assert::That(registro3->getOffsets()->size(), Is().EqualTo(0));
		hashExtensible->exportarTxt("specEliminar");
		delete registro3;


		//Existen la clave y el offset, la cubeta queda vacia, no se puede liberar
		accion = hashExtensible->eliminar("la 3",12463);
		Assert::That(accion, Is().EqualTo(true));

		IRegistroIndice* registro4 = hashExtensible->buscar("la 3");
		Assert::That(registro4->getOffsets()->size(), Is().EqualTo(0));
		hashExtensible->exportarTxt("specEliminar");
		delete registro4;



		}
};
